package com.game.grid;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;
import java.util.Random;

import javax.microedition.khronos.opengles.GL10;

import com.mcodesal.framework.ResourceProvider;
import com.mcodesal.framework.ResourceProvider.Texture;

public class ParticleSystem {
	private Particle[] mParticles;
	private int PARTICLECOUNT = 500;
	private float GRAVITY = 10f;
	private float PARTICLESIZE = 20f;
	private float FLOOR = 10.0f;
	public float x, y, z = -1000;
	private long lastTime;
	private FloatBuffer mVertexBuffer;
	private ShortBuffer mIndexBuffer;
	private FloatBuffer mTextureBuffer;
	private Random gen;
	private int mScreenWidth = -500;
	private int mScreenHeight = -500;
	private int mTextureID;
	
	public ParticleSystem() {
		mParticles = new Particle[PARTICLECOUNT];
		mTextureID = ResourceProvider.getInstance().getTexture(Texture.FIRE_PARTICLE);
		gen = new Random(System.currentTimeMillis());
		for (int i =0; i < PARTICLECOUNT; i++) {
			mParticles[i] = new Particle();
			initParticle(i);
		}
		//a simple triangle sort of looks like
		float[] coords = {-PARTICLESIZE,0.0f,0.0f,
						PARTICLESIZE,0.0f,0.0f,
						0.0f,2*PARTICLESIZE*.86603f,0.0f}; //This makes it an equilateral triangle
		short[] icoords = {0,1,2};
		
		float texture[] = {
		        // Mapping coordinates for the vertices
		        0.0f, 0.0f,    
		        1.0f, 0.0f,   
		        0.5f, 0.86603f,     
		};
		
		mVertexBuffer = makeFloatBuffer(coords);
		mIndexBuffer = makeShortBuffer(icoords);
		mTextureBuffer = makeFloatBuffer(texture);
		
		
		lastTime = System.currentTimeMillis();
	}
	
	public void setPosition(float newX, float newY, float newZ) {
		x = newX;
		y = newY;
		z = newZ;
	}
	
	public void initialize(int width, int height) {
		mScreenWidth = width;
		mScreenHeight = height;
	}
	
	public void draw(GL10 gl) {
		gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureID);
		
        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
        gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
        gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE);
        
        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mVertexBuffer);
        gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, mTextureBuffer);
        //gl.glColor4f(1f, 1f, 1f, 1f);
        for (int i = 0; i < PARTICLECOUNT; i++) {
            gl.glPushMatrix();
            gl.glTranslatef(mParticles[i].x, mParticles[i].y, mParticles[i].z);
            gl.glDrawElements(GL10.GL_TRIANGLES, 3, GL10.GL_UNSIGNED_SHORT, mIndexBuffer);
            gl.glPopMatrix();
        }
        gl.glBlendFunc(GL10.GL_ONE, GL10.GL_ONE_MINUS_SRC_ALPHA);
        gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
		gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
    }
	private void initParticle(int i) {
		//loop through all the particles and create new instances of each one
		mParticles[i].x = gen.nextFloat()*(float)mScreenWidth;
		mParticles[i].y = this.y;
		mParticles[i].z = 0f+gen.nextFloat();
		// random x speed between -15 and 15
		mParticles [i].dx = (gen.nextFloat()*30f) - 15f;
		// random y between 10 and 40
		mParticles [i].dy = (gen.nextFloat()*30)+10f;
		mParticles[i].dz = 0;
	}
	//Do moving here
	public void update() {
		
		//calculate time between frames in seconds
		long currentTime = System.currentTimeMillis();
		float timeFrame = (currentTime - lastTime)/1000f;
		//replace last time with current time
		lastTime = currentTime;
		
		// move the particles
        // first apply gravity to the z speed
        // second move the particle according to its speed and time frame
        // third re-init a particle if it has gone below the 'floor'
		for(int i = 0; i < PARTICLECOUNT; i++) {
			// apply a gravity to the z speed, in this case 
            mParticles[i].dy = mParticles[i].dy - (GRAVITY*timeFrame);

            // move the particle according to it's speed
            mParticles[i].x = mParticles[i].x + (mParticles[i].dx*timeFrame);
            mParticles[i].y = mParticles[i].y + (mParticles[i].dy*timeFrame);
            mParticles[i].z = mParticles[i].z + (mParticles[i].dz*timeFrame);

            // if the particle hits the 'floor' respawn it
            if (mParticles[i].y < this.y-FLOOR || mParticles[i].y > this.y+FLOOR) {
                    initParticle(i);
            }
		}
	}
	
	/*
	 **************************
	 *    Helper Functions    *
	 **************************
	 */
	//use to make native order buffers
	private FloatBuffer makeFloatBuffer(float[] arr) {
		ByteBuffer bb = ByteBuffer.allocateDirect(arr.length*4);
		bb.order(ByteOrder.nativeOrder());
		FloatBuffer fb = bb.asFloatBuffer();
		fb.put(arr);
		fb.position(0);
		return fb;
	}
		
	//use to make native order buffers
	private ShortBuffer makeShortBuffer(short[] arr) {
		ByteBuffer bb = ByteBuffer.allocateDirect(arr.length*4);
		bb.order(ByteOrder.nativeOrder());
		ShortBuffer ib = bb.asShortBuffer();
		ib.put(arr);
		ib.position(0);
		return ib;
	}
}
